#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <cerrno>
#include <cstring>
#include <unistd.h>
#include <cstdlib>
#include <cstdio>


// 共享内存，需要先利用系统接口来得到对应的共享内存，然后客户端和服务器都各自运行。
// 依旧采用服务器控制共享内存的释放和划分。
#define PATH_NAME "." //.代表了当前路径.
#define PROJ_ID 0x1024
#define MEM_SIZE 4096

// 一个专门拿取KEY的函数

key_t Getkey(const char *path, int pjid)
{
	int ret = ftok(path, pjid);
	if (ret != -1)	return ret;
	else
	{
		std::cerr << "can't get key\n"
				  << errno << strerror(errno) << std::endl;
		exit(1);
	}
}

// 一个专门创建共享内存的函数,只创建新的共享内存，而非获取
int CreatShm(key_t key)
{
	int ret = shmget(key, MEM_SIZE,IPC_CREAT | IPC_EXCL| 0600);
	if (ret != -1)	return ret;
	else
	{
		std::cerr << "已存在对应共享内存！不要再新建啦！"
				  << errno << strerror(errno) << std::endl;
		exit(1);
	}
}

//一个专门获取共享内存的函数，返回的就是共享内存的地址。
int GetShm(key_t key)
{
	int ret = shmget(key,MEM_SIZE,IPC_CREAT);
		if (ret != -1)	return ret;
	else
	{
		std::cerr << "无法获取对应共享内存！"
				  << errno << strerror(errno) << std::endl;
		exit(1);
	}
}

//返回的void* 即共享内存的起始地址，可以经过强制类型转换达到访问对应存储数据类型的功能。
void* AttachShm(int shmid)
{
	void * mem = shmat(shmid,nullptr,0);//由于是64位操作系统，对应指针的大小是8
	if((long long)mem == -1L)//所以检查的时候需要使用Long Long类型来检查
    {
        std::cerr <<"shmat: "<< errno << ":" << strerror(errno) << std::endl;
        exit(3);
    }
    return mem;

}
 
int DetachShm(void* shmaddr)
{
	int ret = shmdt(shmaddr);
		if (ret != -1)	return ret;
	else
	{
		std::cerr << "去关联失败！"
				  << errno << strerror(errno) << std::endl;
		exit(1);
	}
}


void delShm(int shmid){  
    if(shmctl(shmid, IPC_RMID, nullptr) == -1)   
    { 
        std::cerr << errno << " : " << strerror(errno) << std::endl;  
    }
 }